#pragma once
#include <string>
#include <jsoncpp/json.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "socket.hpp"
#include "log.hpp"


namespace tr
{


/**
* @brief 自定义消息协议，用于发送 0 ~ 65535 字节内的信息
*        协议： 序列化格式： {"len":3,"msg":"abc"}
               JSON 格式：
               {
                    len: %_len,
                    msg: %_msg
               }
*/
namespace Protocol
{
    // 协议序列化
    std::string encode(const Json::Value& msg)
    { 
        Json::FastWriter _fw;
        Json::Value __t;
        __t["msg"] = msg["msg"].asString();
        std::string __s = _fw.write(__t);
        __t["len"] = __s.size() - 11;
        std::string _res = _fw.write(__t);
        return _res.substr(0,_res.size() - 1); 
    }


    // 反序列化，且要判断消息是否完整传输
    int decode(std::string& msg,Json::Value& _usr_msg)
    {
        Json::Reader _rd;
        int len_p = msg.find("\"len\":");
        int msg_p = msg.find("\"msg\":");
        if(len_p == std::string::npos or 
            msg_p == std::string::npos)
            return 0; // 还不能构成一个完整的消息
    
        int msg_len = atoi(msg.substr(len_p + 6,msg_p - len_p - 7).c_str());
        if(msg_p + 8 + msg_len >= msg.size())return 0; // 不是一个完整的消息
        // 到此为止确定收到了一个完整消息
        int sz = msg_p + 9 + msg_len;
        if(!_rd.parse(msg.substr(0,sz),_usr_msg))
        {
            log(WARNING) << "Parse user msg error." << std::endl;
            return -1;   // 反序列化失败
        }
        msg.erase(0,sz);
        return 1;
    }

    /**
     * @brief 从指定 socket 接收用户信息，保证返回一份完整的用户数据
     * @param sock 接收数据的 socket
     * @param msg 输出型参数，收到的 JSON 数据
     * @return 接收成功返回 1，信息接收错误返回 -1，用户断开连接返回 0。
    */
    int recv(tcp_socket& sock,Json::Value& msg)
    {
        for(;;)
        {
            int _ret = decode(sock._m_buffer,msg);
            if(_ret == 1) return 1;   // 信息接收成功
            else if(_ret == -1) return -1; // 反序列化失败

            // 没有收到完整信息，继续接收信息
            char buff[1024];
            ssize_t _n = ::recv(sock._m_sockfd,buff,sizeof(buff) - 1,0);
            if(_n > 0)
            {
                buff[_n] = 0;
                sock._m_buffer += buff;
                continue;
            }
            if(_n == 0)
            {
                log(INFO) << "User closed the socket." << std::endl;
                return 0;
            }

            // _n < 0
            log(WARNING) << "Recv info from user [IP:"  \
        << sock.get_ip() << ",Port:" << sock.get_port() << "]error." \
        << std::endl;
            return -1;
        }
    }

    // 向指定 socket 发送 Json 数据
    int send(const tcp_socket& sock,const Json::Value& msg)
    {
        std::string buff = encode(msg);
        int ret = ::send(sock._m_sockfd,buff.c_str(),buff.size(),0);
        return ret;
    }
};


} // end of tr